
#include "mc31xx_hal_mux.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */

MuxCB_S g_stAllMux[HAL_CFG_MUX_LIMIT];                              //所有表的控制结构体数组头部，初始化时分配空间
HAL_DL_LIST g_stUnusedMuxList;                                      //未使用的锁都挂在此链表

//模块初始化
uint32_t HAL_MUX_Init(void)
{
    MuxCB_S* pstMuxNode;
    uint32_t   uwIndex;

    HAL_ListInit(&g_stUnusedMuxList);                               //先初始化锁未使用链表

    for (uwIndex = 0; uwIndex < HAL_CFG_MUX_LIMIT; uwIndex++)       //初始化所有锁
    {
        pstMuxNode = (MuxCB_S*)&g_stAllMux[uwIndex];
        pstMuxNode->id = uwIndex;                                   //分配锁id
        pstMuxNode->sta = HAL_MUX_UNUSED;                           //未使用状态
        HAL_ListTailInsert(&g_stUnusedMuxList, &pstMuxNode->list);  //全部挂入未使用表
    }
    return HAL_OK;
}

//创建锁
uint32_t HAL_MUX_Create(uint32_t* puwMuxHandle)
{
    MuxCB_S* pstMuxCreated;
    HAL_DL_LIST* pstUnusedMux;

    if (NULL == puwMuxHandle)
    {
        return HAL_ERRNO_MUX_PTR_NULL;
    }
    __HAL_LOCK_MUX();                                               //申请使用互斥锁模块
    if (HAL_ListEmpty(&g_stUnusedMuxList))                          //寻找未使用的锁
    {
        __HAL_UNLOCK_MUX();
        return HAL_ERRNO_MUX_ALL_BUSY;
    }

    pstUnusedMux = HAL_DL_LIST_FIRST(&g_stUnusedMuxList);           //获取未使用的第一个锁
    HAL_ListDelete(pstUnusedMux);                                   //从未使用链表中移除
    pstMuxCreated = (__HAL_GET_MUX_FROM_LIST(pstUnusedMux));        //获取该链表所在结构体地址
    pstMuxCreated->count = 0;                                       //持有锁的线程锁申请次数0
    pstMuxCreated->sta = HAL_MUX_USED;                              //将锁标记为已使用
    pstMuxCreated->owner = (ThreadCB_S*)NULL;                       //还没有拥有者
    HAL_ListInit(&pstMuxCreated->list);                             //初始化链表
    *puwMuxHandle = (uint32_t)pstMuxCreated->id;                         //确定句柄
    __HAL_UNLOCK_MUX();
    return HAL_OK;
}

//删除锁，将锁恢复到未使用状态
uint32_t HAL_MUX_Delete(uint32_t uwMuxHandle)    
{
    MuxCB_S* pstMuxDeleted;

    if (uwMuxHandle >= (uint32_t)HAL_CFG_MUX_LIMIT)                      //校验锁id是否合法
    {
        return HAL_ERRNO_MUX_INVALID;
    }

    pstMuxDeleted = __HAL_GET_MUX(uwMuxHandle);                     //通过锁id获取锁控制结构地址
    __HAL_LOCK_MUX();
    if (HAL_MUX_UNUSED == pstMuxDeleted->sta)                       //检验锁状态，如果不是已使用，就说明出错了
    {
        __HAL_UNLOCK_MUX();
        return HAL_ERRNO_MUX_INVALID;
    }

    if (!HAL_ListEmpty(&pstMuxDeleted->list) || pstMuxDeleted->count)//如果链表上挂了线程或者锁申请次数不为0，说明正在锁着，不能释放
    {
        __HAL_UNLOCK_MUX();
        return HAL_ERRNO_MUX_PENDED;
    }

    HAL_ListAdd(&g_stUnusedMuxList, &pstMuxDeleted->list);          //将锁挂到未使用表
    pstMuxDeleted->sta = HAL_MUX_UNUSED;                            //将锁的状态改为未使用

    __HAL_UNLOCK_MUX();                                        

    return HAL_OK;
}

//申请锁
uint32_t HAL_MUX_Pend(uint32_t uwMuxHandle, uint32_t uwTimeout)
{
    MuxCB_S* pstMuxPended;
    uint32_t start_tick=CORE_CNT;
    uint32_t ticks= 1000 * SYS_CORE_CLK_MHZ/4;

    if (uwMuxHandle >= (uint32_t)HAL_CFG_MUX_LIMIT)                      //判断锁id是否合法
    {
        return HAL_ERRNO_MUX_INVALID;
    }

    pstMuxPended = __HAL_GET_MUX(uwMuxHandle);                      //通过锁id获取控制结构
    __HAL_LOCK_MUX();                    

    // {   //调试打印锁上挂的线程id
    //     ThreadCB_S* item;
    //     void uart8_send(u8* buf,u16 len);
    //     HAL_DL_LIST_FOR_EACH_ENTRY(item, &pstMuxPended->list, ThreadCB_S,list_mux) {
    //         u8 buf[1];
    //         buf[0] = item->id + 0x30;
    //         uart8_send(buf,1);
    //         buf[0] = '\r';
    //         uart8_send(buf, 1);
    //         buf[0] = '\n';
    //         uart8_send(buf, 1);
    //     }
    // }

    if (HAL_MUX_UNUSED == pstMuxPended->sta)                        //校验锁状态
    {
        __HAL_UNLOCK_MUX();
        return HAL_ERRNO_MUX_INVALID;
    }
    
    if (pstMuxPended->count == 0)                                   //第一次申请锁
    {
        pstMuxPended->count++;
        pstMuxPended->owner = &g_stAllThread[THREAD_ID];            //当前线程关联到锁
        __HAL_UNLOCK_MUX();                            
        return HAL_OK;
    }

    if (pstMuxPended->owner == &g_stAllThread[THREAD_ID])           //允许递归申请申请锁
    {
        pstMuxPended->count++;                                      //记录递归次数
        __HAL_UNLOCK_MUX();                                
        return HAL_OK;
    }

    /**************   既不是第一个申请锁的，也不是持有锁的线程   **************/
    if (uwTimeout==HAL_NO_WAIT)                                     //非阻塞锁，直接返回
    {
        __HAL_UNLOCK_MUX();                                
        return HAL_ERRNO_MUX_UNAVAILABLE;
    }

    /*
    预留位置
    这里可以添加线程状态的修改
    */

    HAL_ListTailInsert(&pstMuxPended->list, (HAL_DL_LIST *)&g_stAllThread[THREAD_ID].list_mux);//将当前线程的挂起节点链表置入当前锁

    __HAL_UNLOCK_MUX();                                             //释放互斥锁模块

    if (uwTimeout == HAL_WAIT_FOREVER)                              //无限等待，如果获取到锁能立刻响应
    {
        while (1)
        {
            if (pstMuxPended->owner == &g_stAllThread[THREAD_ID]) 
            {
                return HAL_OK;
            }
        }
    }
    else 
    {
        while (1) {                                       //等待直到获取到锁或超时
            if (pstMuxPended->owner == &g_stAllThread[THREAD_ID]) {
                return HAL_OK;
            }
            if(CORE_CNT-start_tick>=ticks) {
                start_tick=CORE_CNT;
                uwTimeout--;
                if(uwTimeout==0){
                    break;
                }
            }
        }
    }
    __HAL_LOCK_MUX();                                               //申请操作锁
    if (pstMuxPended->owner == &g_stAllThread[THREAD_ID]) {         //再次判断
        return HAL_OK;
    }
    else{
        HAL_ListDelete((HAL_DL_LIST *)&g_stAllThread[THREAD_ID].list_mux);
    }
    __HAL_UNLOCK_MUX();    

    return HAL_ERRNO_MUX_TIMEOUT;       
}

//释放锁
uint32_t HAL_MUX_Post(uint32_t uwMuxHandle)
{
    MuxCB_S* pstMuxPosted = __HAL_GET_MUX(uwMuxHandle);
    ThreadCB_S* pstResumedTask =(ThreadCB_S*) NULL;

    __HAL_LOCK_MUX();                                

    if ((uwMuxHandle >= (uint32_t)HAL_CFG_MUX_LIMIT) ||
        (HAL_MUX_UNUSED == pstMuxPosted->sta))                      //判断锁id和锁状态是否合法
    {
        __HAL_UNLOCK_MUX();
        return HAL_ERRNO_MUX_INVALID;
    }

    if ((pstMuxPosted->count == 0) || (pstMuxPosted->owner != &g_stAllThread[THREAD_ID])) //如果锁没用过，或者本线程就没申请到锁，无法释放，返回错误
    {
        __HAL_UNLOCK_MUX();
        return HAL_ERRNO_MUX_INVALID;
    }

    if (--(pstMuxPosted->count) != 0)                               //当前线程锁递归次数减一，如果当前线程递归了多次，且不是最后一次释放，直接返回成功
    {
        __HAL_UNLOCK_MUX();
        return HAL_OK;
    }

    if (!HAL_ListEmpty(&pstMuxPosted->list))                        //如果锁的链表非空，摘取下一个申请锁的线程
    {
        HAL_DL_LIST* pstNodeDelete= HAL_DL_LIST_FIRST(&(pstMuxPosted->list));   //从锁链表获取第一个被阻塞的线程
        HAL_ListDelete(pstNodeDelete);                                          //将其从表中删除
        pstResumedTask=HAL_DL_LIST_ENTRY(pstNodeDelete, ThreadCB_S, list_mux);  //获取对应任务控制块

        pstMuxPosted->count = 1;                                    //持有锁线程申请锁的次数恢复到1
        pstMuxPosted->owner = pstResumedTask;                       //切换锁持有者

        __HAL_UNLOCK_MUX();                    
    }
    else                                                            //此时锁申请次数是0，如果没有其他线程在申请锁，则直接返回，不需要再做处理
    {
        __HAL_UNLOCK_MUX();
    }

    return HAL_OK;
}


#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
